/****************************************************************************//**
  \file bootloader.c

  \brief Implementation of bootloader state machine.

  \author
    Atmel Corporation: http://www.atmel.com \n
    Support email: avr@atmel.com

  Copyright (c) 2008-2013, Atmel Corporation. All rights reserved.
  Licensed under Atmel's Limited License Agreement (BitCloudTM).

  \internal
  History:
    2/04/09 A. Khromykh - Created
*******************************************************************************/
/******************************************************************************
                   Includes section
******************************************************************************/
#include <stdbool.h>
#include "bootStructure.h"
#include "hardwareInit.h"
#include "uart.h"
#include "srecParser.h"
#include "bootloader.h"

#include <avr/eeprom.h>
#include <avr/pgmspace.h>
#include <avr/fuse.h>
#include <avr/lock.h>
#include <stdlib.h>


/*
FUSES = {
	.low = FUSE_CKSEL3 & FUSE_CKSEL0 & FUSE_SUT0 ,
	.high = FUSE_EESAVE & FUSE_JTAGEN & FUSE_SPIEN & FUSE_BOOTSZ0 & FUSE_BOOTSZ1,// & FUSE_BOOTRST,
	.extended = EFUSE_DEFAULT
};
*/

/*
FUSES = {
	.low = LFUSE_DEFAULT,
	.high = HFUSE_DEFAULT,
	.extended = EFUSE_DEFAULT
};
*/


//LOCKBITS = LB_MODE_1 & BLB0_MODE_1 & BLB1_MODE_2;

/**************************************************************************//**
\brief State machine in the main
******************************************************************************/


//================================================================================

// predefinovana data v eprom
//Application_Info_t app_info;

//================================================================================
// this is only for debugging, when app reset vector is at 0x0000
//================================================================================
volatile __attribute__((section(".reset"), naked, noreturn)) void Reset() 
{
	//UART1_Init(BAUDRATE_115K2);
	//UART1_SendStringPGM(PSTR("No application loaded, starting bootloader\r\n"));
	//UART1_Uninit();
	asm volatile ("jmp 0x1e000" ::);
}

//=== LOADED APPLICATION SETTINGS ===============================================

application_info_t app_info;

//===============================================================================

int main(void) 
{
	bool infinite = false;			// I presume that application is valid and no downloading is required
	uint16_t crc;					// crc variable

	DisableWatchDog();
	loadAppInfo();
	
	UART1_Init(app_info.brd);
	UART1_SendStringPGM(PSTR("Bootloader v1.0a application: "));
	if (app_info.version[0] == 0)
	{
		UART1_SendStringPGM(PSTR("none\r\n"));
	}
	else
	{
		UART1_SendString(app_info.version);
		UART1_SendStringPGM(PSTR("\r\n"));
	}

	// check invalid application, is default after bootloader programmed or crc of application is invalid
	if (app_info.invalid == INVALID)
	{
		UART1_SendStringPGM(PSTR("No or invalid application, please download application\r\n"));
		infinite = true;
	} 
	else 
	{
		UART1_SendStringPGM(PSTR("Calculating program crc ..."));
		crc = ComputeCRC16(app_info.code_size);
		UART1_SendStringPGM(PSTR("done. "));
		
		if (crc == app_info.crc16) 
		{
			UART1_SendStringPGM(PSTR(" CRC OK\r\n"));
			infinite = false;
		} 
		else
		{
			UART1_SendStringPGM(PSTR(" CRC failed, please download application\r\n"));
			app_info.invalid = INVALID;
			storeAppInfo();
		}
	}
			
	srecHandshake(infinite);
	srecProtocol();
	
	asm volatile ("jmp 0x0000" ::);
	//Reset();
}

//==================================================================================================

void loadAppInfo()
{
	eeprom_read_block(&app_info, APP_INFO_ADDRESS, sizeof(application_info_t));

	if (app_info.version[VERSION_NAME_LENGTH] == 0xFF)	// eeprom not initialized
	{
		memset(app_info.version, 0x00, VERSION_NAME_LENGTH+1);
		app_info.code_size = 0;
		app_info.crc16 = 0;
		app_info.invalid = INVALID;
		app_info.brd = BAUDRATE_115K2;
		storeAppInfo();
	}
}

//===================================================================================================

void storeAppInfo()
{
	eeprom_update_block(&app_info, APP_INFO_ADDRESS, sizeof(application_info_t));
}

// eof bootloader.c
